#region Imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using PHSRAG.Insight21.InsightUtilities;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using SearchCriteria = PHSRAG.Insight21.SearchContext.SearchCriteria;
using AgreementsConstants = PHSRAG.Insight21.InsightUtilities.Constants.AgreementsConstants;
using BudgetConstants = PHSRAG.Insight21.InsightUtilities.Constants.BudgetInfoConstants;
using GenerateKey = PHSRAG.Insight21.BusinessObjects.ModuleKey;
#endregion

namespace PHSRAG.Insight21.Agreements
{
	#region Class BudgetDetails
	/// <summary>
	/// The BudgetDetails class supports loading of all budget details information
	/// for the given fund number and the month ending date.
	/// </summary>
	public class BudgetDetails:BO.BusinessObject
	{
		#region Constants
		private static string	BudgetDetailsKey				= GenerateKey.MakeKey("BudgetDetails_F1EB0573-FE58-4044-B6D5-0B2A72D0FD0F",GenerateKey.Agreement);
		private const string	DomainUserIDParamName			= "@domainUserId";
		private const string	FundNumberParamName				= "@fundNumber";
		private const string	MonthEndingDateParamName		= "@monthEndingDate";
		private const string	BudgetYearParamName				= "@budgetYear";
		private const string	CumulativeParamName				= "@cumulative";
        private const string    BudgetEndingParamName           = "@BudgetEndingDate";
        private const string    IncludeUserOrdersParamName      = "@IncludeUserOrders";
		private const string	GetRelatedFundsSPROCName		= "GetRelatedFunds";
		private const string	GetBudgetYearsSPROCName			= "GetBudgetYears";
		private const string	GetBudgetDetailsSPROCName		= "GetBudgetDetails";
		private const int		DefaultProgramProjectsFlag		= 1;
		private const int		FwkDomainUserIdArgumentIndex			= 0;
        private const int FundNumberArgumentIndex = 1;
        private const int SearchCriteriaArgumentIndex = 0;
		#endregion

		#region Enumerations (Private)
		// Enumerates the arguments required for loading budget details.
		private enum LoadMethodArgs
		{
			DomainUserID,
			FundNumber,
			MonthEndingDate,
			BudgetYear,
			Cumulative,
            BudgetEndingDate,
            IncludeUserOrders,
			Count
		}
		//Enumarated the table index in the datacontainer
		private enum TableIndex
		{
			Category,
			Accounts,
			DirectCosts,
			IndirectCosts,
			Revenue,
			PriorYrBalance,
			ProjectHeader,
			Count
		}
		#endregion

		#region Class Methods
		/// <summary>
		/// Load the related funds for a given fund number
		/// </summary>
		/// <param name="connectionString">The data base connection string</param>
		/// <param name="args">Argument list with the whole set of agreement search criteria
		/// Is expected to contain a fundNumber</param>
		/// <returns>DataTable with a list of fund numbers</returns>
		public static DataTable LoadRelatedFunds(string connectionString, params object[] args)
		{
			try
			{
				SearchCriteria searchCriteria = (SearchCriteria) args[0];

				object fundNumber	= searchCriteria[Constants.FundIDKey];

				if((fundNumber == null) || ((string)fundNumber == string.Empty || (string)fundNumber == "0"))
					throw new Exception(@"A Fund Number is required to load Related Fund Numbers.");

				return DataAccess.GetDataTable(connectionString, GetRelatedFundsSPROCName,
					DataAccess.BuildSqlParameterArray(
					"@fundNumber", SqlDbType.VarChar, fundNumber.ToString()
					));
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in loading related funds",ex);
			}
		}
		/// <summary>
		/// Load the list of budget years for the given fund number
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">Is expceted to contain the FundNumber</param>
		/// <returns>Datatable with a list of budget years</returns>
		public static DataTable LoadBudgetYears(string connectionString, params object[] args)
		{
			try
			{
				return DataAccess.GetDataTable(connectionString, GetBudgetYearsSPROCName,
					DataAccess.BuildSqlParameterArray(
                    "@fwkDomainUserId", SqlDbType.Int, args[FwkDomainUserIdArgumentIndex],
					"@fundNumber",SqlDbType.VarChar,args[FundNumberArgumentIndex]));
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in loading budget years",ex);
			}
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Parameterized constructor, Initialize the base class with the active cache policy
		/// </summary>
		/// <param name="cachePolicy">Active cache policy</param>
		public BudgetDetails():base(null)
		{
		}
		#endregion

		#region Public Properties
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return BudgetDetailsKey; } }
		#endregion

		#region BusinessObject Methods
		/// <summary>
		/// Load the current instance with budget details data for the current user.
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">Is expected to contain the domain user ID, the fund number and the month ending date
		/// The budget year is an optional parameter</param>
		public override void Load(string connectionString, params object[] args)
		{
			if (!args.Length.Equals((int)LoadMethodArgs.Count))
				throw new Exception(String.Format("Budget details requires {0} parameters", 
					((int)LoadMethodArgs.Count).ToString()));
			try
			{				
                DataContainer = Utility.DataAccess.GetDataSet(connectionString, GetBudgetDetailsSPROCName,
                    Utility.DataAccess.BuildSqlParameterArray
                    (DomainUserIDParamName, SqlDbType.Int, args[(int)LoadMethodArgs.DomainUserID]
                    , FundNumberParamName, SqlDbType.VarChar, args[(int)LoadMethodArgs.FundNumber]
                    , MonthEndingDateParamName, SqlDbType.VarChar, args[(int)LoadMethodArgs.MonthEndingDate]
                    , BudgetYearParamName, SqlDbType.Int, args[(int)LoadMethodArgs.BudgetYear]
                    , CumulativeParamName, SqlDbType.Int, args[(int)LoadMethodArgs.Cumulative]
                    , BudgetEndingParamName, SqlDbType.DateTime, args[(int)LoadMethodArgs.BudgetEndingDate]
                    , IncludeUserOrdersParamName, SqlDbType.Bit, args[(int)LoadMethodArgs.IncludeUserOrders]));

				DataSet budgetDetailsData = DataContainer;

				if (budgetDetailsData.Tables.Count != (int)TableIndex.Count)
					throw new Exception(@"Failed to load budget details.");
				else
				{
					budgetDetailsData.Tables[(int)TableIndex.Category].TableName	= 
						BudgetConstants.CategoryTableName;
					budgetDetailsData.Tables[(int)TableIndex.Accounts].TableName	= 
						AgreementsConstants.AccountsTableName;
					budgetDetailsData.Tables[(int)TableIndex.DirectCosts].TableName = 
						AgreementsConstants.DirectCostsTableName;
					budgetDetailsData.Tables[(int)TableIndex.IndirectCosts].TableName = 
						AgreementsConstants.IndirectCostsTableName;
					budgetDetailsData.Tables[(int)TableIndex.Revenue].TableName =	
						AgreementsConstants.RevenueTableName;					
					budgetDetailsData.Tables[(int)TableIndex.PriorYrBalance].TableName =	
						AgreementsConstants.PriorYrBalanceTableName;
					budgetDetailsData.Tables[(int)TableIndex.ProjectHeader].TableName =	
						AgreementsConstants.ProjectHeader;

					DataTable totalCostsTable = new DataTable(AgreementsConstants.TotalCostsTableName);
					AddCostsSchema(totalCostsTable);			
					budgetDetailsData.Tables.Add(totalCostsTable);
		
					DataTable cashBalanceTable = new DataTable(AgreementsConstants.CashBalanceTableName);
					AddCostsSchema(cashBalanceTable);
					budgetDetailsData.Tables.Add(cashBalanceTable);

					BudgetOverview.ComputeTotals(budgetDetailsData);
				}
			}
			catch(Exception ex)
			{
				throw new Exception(@"Error in loading Budget Details",ex);
			}
		}
		#endregion

		#region Private methods
		/// <summary>
		/// Add the costs table schema
		/// </summary>
		/// <param name="dataTable">Datatable to which the new schema is to be added</param>
		private void AddCostsSchema(DataTable dataTable)
		{
			dataTable.Columns.Add
				(new DataColumn("Budget",typeof(System.Decimal)));
			dataTable.Columns.Add
				(new DataColumn("Expense",typeof(System.Decimal)));
			dataTable.Columns.Add
				(new DataColumn("Encumbrance",typeof(System.Decimal)));
			dataTable.Columns.Add
				(new DataColumn("BalanceAvailable",typeof(System.Decimal)));
		}
		#endregion
	}
	#endregion
}